
#include "precomp.h"

VOID SCSICompleteIrp (
ULONG Handle , PVOID Ctx , UCHAR ScsiStatus , PUCHAR SenseData , ULONG SenseLen);

NTSTATUS uFDOIoCtl (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	NTSTATUS				Status = STATUS_SUCCESS;
	PIO_STACK_LOCATION		Stack;
	PDEVICE_OBJECT			DevPdo;
	PFDO_EXT				FdoExt;
	PPDO_EXT				PdoExt;
	
	Stack = IoGetCurrentIrpStackLocation( Irp );
	FdoExt = (PFDO_EXT)DeviceObject->DeviceExtension;
	
	switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
	{
		case IOCTL_ISCSI_CREATE_SESSION:
		{
			ULONG				Len;
			PUCHAR				Target;
			PVOID				Session;
			USCSI_CALL_BACK		C = {0};
				
			Target = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;				
	
			if ( Target[Stack->Parameters.DeviceIoControl.InputBufferLength-1] != '\0' ||
				( Len = strlen ( Target ) ) != Stack->Parameters.DeviceIoControl.InputBufferLength -1 )
			{
				Status = STATUS_INVALID_PARAMETER;
			}
			else
			{
				Status = IoCreateDevice(DeviceObject->DriverObject, 
  										sizeof(PDO_EXT) ,				//user size 							   							
  										NULL,   						//Name	
  										FILE_DEVICE_UNKNOWN,            //Device Type
  										FILE_DEVICE_SECURE_OPEN|
  										FILE_AUTOGENERATED_DEVICE_NAME, //Characteristics
  										TRUE,                           //Exclusive
  										&DevPdo);
   											
  				if ( NT_SUCCESS(Status) )
  				{
  					PdoExt = (PPDO_EXT)DevPdo->DeviceExtension;
  					
  					InitializeListHead ( &PdoExt->PDOList);
  					PdoExt->IsFDO = FALSE;
  					PdoExt->Reported = FALSE;
  					PdoExt->Self = DevPdo;
   						   							
  					PdoExt->Target = 
  						ExAllocatePoolWithTag ( PagedPool , Len + 1 , USCSI_TAG );
  					RtlCopyMemory ( PdoExt->Target , Target , Len + 1 );   							
   						
  					C.CompleteCmd = SCSICompleteIrp;
  					C.CompleteCtx = PdoExt;
  					PdoExt->Session = uSCSICreateSession ( PdoExt->Target , &C);
   						
  					if ( PdoExt->Session )
  					{	 							  							
  						ExInterlockedInsertTailList ( &FdoExt->PDOList , 
   													  &PdoExt->PDOList,
   													  &FdoExt->PDOLock);
   						FdoExt->PDOCount++;   						
   						IoInvalidateDeviceRelations ( FdoExt->LowerDev , BusRelations );
   						//DbgPrint("%s Session to Target %s Created\n" , __FUNCTION__, PdoExt->Target );  						
   					}
   					else
   					{
   						if ( DevPdo )
   							IoDeleteDevice ( DevPdo );
   						Status = STATUS_UNSUCCESSFUL;
   					}
   				}			
			}
		}
		break;
		
		case IOCTL_ISCSI_ADD_TARGETS:
		{
			PTGTS	Tgts;
			PTGT	Tgt;
			ULONG	i;
			Tgts = (PTGTS)Irp->AssociatedIrp.SystemBuffer;

			if ( sizeof (TGTS) > Stack->Parameters.DeviceIoControl.InputBufferLength)
				Status = STATUS_BUFFER_TOO_SMALL;

			else if ( Tgts->Size != Stack->Parameters.DeviceIoControl.InputBufferLength )
				Status = STATUS_INVALID_PARAMETER;
			
			else
			{
				Tgt = (PTGT)(Tgts + 1);
				for ( i = 0 ; i < Tgts->Count ; i++ )
				{
					uSCSIAddTarget ( Tgt->TargetName , Tgt->Addr , Tgt->Port );
					Tgt++;
				}
			}
		}		
		break;
		
		case IOCTL_ISCSI_GET_TARGETS:
		{
			PTGTS	Tgts;
			PTGT	Tgt;
			Tgts = (PTGTS)Irp->AssociatedIrp.SystemBuffer;

			if ( sizeof (TGTS) > Stack->Parameters.DeviceIoControl.InputBufferLength)
				Status = STATUS_BUFFER_TOO_SMALL;
				
			else if ( !Tgts->Size )
			{
				Tgts->Size = uSCSIGetTargetsSize();
				Irp->IoStatus.Information = Stack->Parameters.DeviceIoControl.OutputBufferLength;
			}
			
			else if ( Tgts->Size != Stack->Parameters.DeviceIoControl.InputBufferLength )
				Status = STATUS_INVALID_PARAMETER;
			
			else 
			{
				Status = uSCSIPopTargets ( Tgts );
				Irp->IoStatus.Information = Stack->Parameters.DeviceIoControl.OutputBufferLength;
			}
		}
		break;
	}

	Irp->IoStatus.Status = Status;
	IoCompleteRequest ( Irp , IO_NO_INCREMENT );
	return Status;
}

//
//
//

NTSTATUS uPDOIoCtl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
	NTSTATUS				Status = STATUS_SUCCESS;
	PIO_STACK_LOCATION		Stack;
	PPDO_EXT				Ext;
	
	Stack = IoGetCurrentIrpStackLocation( Irp );
	Ext = (PPDO_EXT)DeviceObject->DeviceExtension;
		
	switch (Stack->Parameters.DeviceIoControl.IoControlCode)
	{
		case IOCTL_STORAGE_QUERY_PROPERTY:
			{
				PSTORAGE_PROPERTY_QUERY	PropQuery;
				PSTORAGE_DESCRIPTOR_HEADER	DescriptorHeader;
				PSTORAGE_DEVICE_DESCRIPTOR	DeviceDescriptor;
				PSTORAGE_ADAPTER_DESCRIPTOR	AdapterDescriptor;
				
				PropQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
				
				if (sizeof (STORAGE_PROPERTY_QUERY) > 
					Stack->Parameters.DeviceIoControl.InputBufferLength)
				{
					Status = STATUS_INVALID_PARAMETER;
					Irp->IoStatus.Information = 0;
				}
				else
				{
					/*
					PropertyId:
					StorageDeviceProperty = 0,
    				StorageAdapterProperty,
    				StorageDeviceIdProperty,
    				StorageDeviceUniqueIdProperty,              // See storduid.h for details
    				StorageDeviceWriteCacheProperty,
    				StorageMiniportProperty,
    				StorageAccessAlignmentProperty,
    				StorageDeviceSeekPenaltyProperty,
    				StorageDeviceTrimProperty,
    				StorageDeviceWriteAggregationProperty
					*/
					/*
					QueryType:
					PropertyStandardQuery = 0, 
  					PropertyExistsQuery, 
  					PropertyMaskQuery, 
  					PropertyQueryMaxDefined
					*/
					DbgPrint("%s IOCTL_STORAGE_QUERY_PROPERTY PropertyId=0x%X QueryType=0x%X\n" , 
					__FUNCTION__ , PropQuery->PropertyId , PropQuery->QueryType);
						
					if (StorageDeviceProperty == PropQuery->PropertyId)
					{					
						
						if ( sizeof (STORAGE_DESCRIPTOR_HEADER) == 
							Stack->Parameters.DeviceIoControl.OutputBufferLength)
						{
							DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
							DescriptorHeader->Version = 1;
							DescriptorHeader->Size = 
								sizeof (STORAGE_DEVICE_DESCRIPTOR)+22;
							Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
						}
						else
						{
							DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
						
							DeviceDescriptor->Version = 1;
							DeviceDescriptor->Size = sizeof (STORAGE_DEVICE_DESCRIPTOR);
							DeviceDescriptor->DeviceType = DIRECT_ACCESS_DEVICE; 
							DeviceDescriptor->DeviceTypeModifier = 0;
							DeviceDescriptor->RemovableMedia = FALSE;
							DeviceDescriptor->CommandQueueing = FALSE;
							DeviceDescriptor->VendorIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
							DeviceDescriptor->ProductIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+8;
							DeviceDescriptor->ProductRevisionOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+14;
							DeviceDescriptor->SerialNumberOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR)+17;
							DeviceDescriptor->BusType = BusTypeiScsi;
							DeviceDescriptor->RawPropertiesLength = 22;
							RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->VendorIdOffset],"yushang\0",8);
							RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->ProductIdOffset],"uSCSI\0",6);
							RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->ProductRevisionOffset],"r1\0",3);
							RtlCopyMemory(&DeviceDescriptor->RawDeviceProperties[DeviceDescriptor->SerialNumberOffset],"A123\0",5);
							//
							Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR);
						}
					}
					else if ( StorageAdapterProperty == PropQuery->PropertyId )
					{
						if ( sizeof (STORAGE_DESCRIPTOR_HEADER) == 
							Stack->Parameters.DeviceIoControl.OutputBufferLength)
						{
							DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
							DescriptorHeader->Version = 1;
							DescriptorHeader->Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
							Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
						}
						else 
						{
							AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;

							AdapterDescriptor->Version = 20;
							AdapterDescriptor->Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
							AdapterDescriptor->MaximumTransferLength = 0x40*0x1000;//0x40000;
							AdapterDescriptor->MaximumPhysicalPages = 0x41;
							AdapterDescriptor->AlignmentMask = 0x3;
							AdapterDescriptor->AdapterUsesPio = FALSE;
							AdapterDescriptor->AdapterScansDown = FALSE;
							AdapterDescriptor->CommandQueueing = FALSE;
							AdapterDescriptor->AcceleratedTransfer = FALSE;
							AdapterDescriptor->BusType = BusTypeiScsi;
							AdapterDescriptor->BusMajorVersion = 2;
							AdapterDescriptor->BusMinorVersion = 0;		
							Irp->IoStatus.Information = sizeof (STORAGE_ADAPTER_DESCRIPTOR);		
						}			
					}
					else
					{
						DbgPrint("*** IOCTL_STORAGE_QUERY_PROPERTY Unprocessed PropertyId=0x%X\n" , PropQuery->PropertyId);
					}
				}
			}
			break;
			
		case IOCTL_DISK_GET_DRIVE_GEOMETRY:
			{
				PDISK_GEOMETRY Geo = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
				
				DbgPrint("%s IOCTL_DISK_GET_DRIVE_GEOMETRY\n" , __FUNCTION__ );
				
				if (sizeof (DISK_GEOMETRY) > Stack->Parameters.DeviceIoControl.OutputBufferLength)
				{
					Status = STATUS_INVALID_PARAMETER;
					Irp->IoStatus.Information = 0;
				}
				else
				{
					// 256M
					Geo->Cylinders.LowPart = 0x100;
					Geo->Cylinders.HighPart = 0;
					Geo->MediaType = FixedMedia;
					Geo->TracksPerCylinder = 0x100;
					Geo->SectorsPerTrack = 0x4;
					Geo->BytesPerSector  = 0x400;
					Irp->IoStatus.Information = sizeof (DISK_GEOMETRY);
				}
			}
			break;
			
		case IOCTL_SCSI_GET_ADDRESS:
			{
				PSCSI_ADDRESS	Addr;
				Addr = (PSCSI_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
				
				DbgPrint("%s IOCTL_SCSI_GET_ADDRESS\n" , __FUNCTION__ );
				
				if ( sizeof (SCSI_ADDRESS) > Stack->Parameters.DeviceIoControl.OutputBufferLength )
				{
					Status = STATUS_INVALID_PARAMETER;
					Irp->IoStatus.Information = 0;
				}
				else
				{
					Addr->Length = sizeof (SCSI_ADDRESS);
					Addr->PortNumber = 1;
					Addr->PathId = 1;
					Addr->TargetId = 1;
					Addr->Lun = 0;
					Irp->IoStatus.Information = sizeof (SCSI_ADDRESS);
				}
			}
			break;	
			
		case IOCTL_SCSI_PASS_THROUGH_DIRECT:
			DbgPrint("%s IOCTL_SCSI_PASS_THROUGH_DIRECT\n" , __FUNCTION__ );
			break;	
		
		case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
			DbgPrint("%s IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n" , __FUNCTION__ );
			break;	
		
		case IOCTL_MOUNTDEV_LINK_CREATED:
			DbgPrint("%s IOCTL_MOUNTDEV_LINK_CREATED\n" , __FUNCTION__ );
			break;
		
		case IOCTL_VOLUME_ONLINE:
			DbgPrint("%s IOCTL_VOLUME_ONLINE\n" , __FUNCTION__ );
			break;
		
		case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
			DbgPrint("%s IOCTL_VOLUME_GET_GPT_ATTRIBUTES\n" , __FUNCTION__ );
			break;
		
		case IOCTL_SCSI_MINIPORT:
			{
				PSRB_IO_CONTROL 	IoCtl;
				IoCtl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
			
				DbgPrint("IOCTL_SCSI_MINIPORT HeaderLength=0x%X Signature=%c%c%c%c%c%c%c%c Timeout=0x%X ControlCode=0x%X ReturnCode=0x%X Length=0x%X\n",
				IoCtl->HeaderLength,
				IoCtl->Signature[0],IoCtl->Signature[1],IoCtl->Signature[2],IoCtl->Signature[3],
				IoCtl->Signature[4],IoCtl->Signature[5],IoCtl->Signature[6],IoCtl->Signature[7],
				IoCtl->Timeout , 
				IoCtl->ControlCode,
				IoCtl->ReturnCode,
				IoCtl->Length);
			}
			break;
		//HD Tune Pro 5.0
		/*	
		case IOCTL_ATA_PASS_THROUGH:
			{
				PATA_PASS_THROUGH_EX Pat;
				DbgPrint("%s IOCTL_ATA_PASS_THROUGH\n" , __FUNCTION__ );
				
				if ( sizeof(ATA_PASS_THROUGH_EX) > 
					Stack->Parameters.DeviceIoControl.InputBufferLength )
				{
					Status = STATUS_INVALID_PARAMETER;
				}
				else
				{
					Pat = (PATA_PASS_THROUGH_EX)Irp->AssociatedIrp.SystemBuffer;
					DbgPrint("PathId.TargetId.Lun=0x%X.%X.%X AtaFlags=0x%X DataTransferLength=0x%X\n" , 
					Pat->PathId,Pat->TargetId,Pat->Lun,
					Pat->AtaFlags,Pat->DataTransferLength);
					if ( Pat->AtaFlags & ATA_FLAGS_DATA_IN &&
					     (Pat->DataTransferLength + sizeof(ATA_PASS_THROUGH_EX)) > 
					        Stack->Parameters.DeviceIoControl.InputBufferLength )
						Status = STATUS_INVALID_PARAMETER;
					else
					{
						
					}
				}
				
			}
			break;
			*/
		//ntddft.h
		case FT_BALANCED_READ_MODE:
			Status = STATUS_UNSUCCESSFUL;
			DbgPrint("%s FT_BALANCED_READ_MODE\n" , __FUNCTION__ );
			break;
			
		default:
			DbgPrint("%s *** Unprocessed IoControlCode 0x%X (DevType 0x%X , Function 0x%X)\n" , 
			__FUNCTION__ , 
			Stack->Parameters.DeviceIoControl.IoControlCode,
			DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode),		
			FUNC_CODE(Stack->Parameters.DeviceIoControl.IoControlCode));
			
			break;
	}
	
	Irp->IoStatus.Status = Status;
	IoCompleteRequest ( Irp , IO_NO_INCREMENT );
	return Status;
}

//
// IRP_MJ_DEVICE_CONTROL
//

NTSTATUS uIoCtl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	PCOMMON_EXT	Ext;
	Ext = (PCOMMON_EXT)DeviceObject->DeviceExtension;
	
	if ( Ext->IsFDO )
		return uFDOIoCtl ( DeviceObject , Irp );
	else
		return uPDOIoCtl ( DeviceObject , Irp );
}

